﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.Linq;

namespace MessengerBot
{
    /// <summary>
    /// This is the abstract base class for built-in <see cref="ILogger"/> implementations.
    /// </summary>
    public abstract class LoggerBase : ILogger
    {
        /// <summary>
        /// This field holds the filter used to filter messages.
        /// </summary>
        private readonly Predicate<LogEntry> _Filter;

        /// <summary>
        /// Initializes a new instance of the <see cref="LoggerBase"/> class.
        /// </summary>
        /// <param name="filter">
        /// A predicate that takes a <see cref="LogEntry"/> value and has
        /// to return <c>true</c> for the log entry to be sent to the
        /// log destination.
        /// </param>
        protected LoggerBase(Predicate<LogEntry> filter)
        {
            _Filter = filter;
        }

        #region ILogger Members

        /// <summary>
        /// Logs a single message to the log destination.
        /// </summary>
        /// <param name="level">The level of the message, used for filtering.</param>
        /// <param name="message">The message to log.</param>
        public void Log(LogLevel level, string message)
        {
            if (_Filter != null)
            {
                if (!_Filter(new LogEntry(level, message)))
                    return;
            }

            WriteToLog(level, message);
        }

        #endregion

        /// <summary>
        /// When implemented in a descendant, will output the log message to the log destination.
        /// </summary>
        /// <param name="level">
        /// The level of the message.
        /// </param>
        /// <param name="message">
        /// The message to log.
        /// </param>
        protected abstract void WriteToLog(LogLevel level, string message);

        /// <summary>
        /// Returns a standard format for the given <paramref name="level"/>
        /// and <paramref name="message"/>, including both in a single string.
        /// </summary>
        /// <param name="level">
        /// The level of the message.
        /// </param>
        /// <param name="message">
        /// The message to log.
        /// </param>
        /// <returns>
        /// A string containing both the <paramref name="level"/>
        /// and the <paramref name="message"/>, unless the <paramref name="level"/>
        /// is <see cref="LogLevel.Information"/> in which case only the
        /// <paramref name="message"/> is returned.
        /// </returns>
        protected virtual string StandardFormat(LogLevel level, string message)
        {
            switch (level)
            {
                case LogLevel.Debug:
                    return string.Format(CultureInfo.InvariantCulture, "Debug: {0}", message);

                case LogLevel.Information:
                    return message;

                case LogLevel.Warning:
                    return string.Format(CultureInfo.InvariantCulture, "Warning: {0}", message);

                case LogLevel.Error:
                    return string.Format(CultureInfo.InvariantCulture, "Error: {0}", message);

                default:
                    return string.Format(CultureInfo.InvariantCulture, "Unknown ({0}): {1}", level, message);
            }
        }
    }
}